package net.maku.project.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.fhs.trans.service.impl.TransService;
import lombok.AllArgsConstructor;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import net.maku.framework.common.exception.ServerException;
import net.maku.framework.common.utils.ConvertUtil;
import net.maku.framework.common.utils.DateUtils;
import net.maku.framework.common.utils.ExcelUtils;
import net.maku.framework.common.utils.PageResult;
import net.maku.framework.mybatis.service.impl.BaseServiceImpl;
import net.maku.framework.security.user.SecurityUser;
import net.maku.project.convert.InfoConvert;
import net.maku.project.dao.InfoDao;
import net.maku.project.dao.ProcessStatesDao;
import net.maku.project.entity.*;
import net.maku.project.query.InfoQuery;
import net.maku.project.service.*;
import net.maku.project.vo.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.Duration;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 项目信息
 *
 * @author lvpb lv941226@gmail.com
 * @since 1.0.0 2024-07-08
 */
@Slf4j
@Service
@AllArgsConstructor
public class InfoServiceImpl extends BaseServiceImpl<InfoDao, InfoEntity> implements InfoService {


    private final ProcessStagesService processStagesService;
    private final StageService stageService;
    private final ProcessStepsService processStepsService;
    private final ProcessStatesService processStatesService;
    private final TransService transService;
    @Autowired
    private ProcessStatesDao processStatesDao;

    private final static Long FIRST_STAGE_ID = 1L;
    private final static Integer NEED_CONFIRM = 1;
    private final static String DEFAULT_CURRENT_STATUS = "待开始";
    private final static String FINISH_STATUS = "已完成";
    private final static String ONE_STAGE_STATUS = "项目对接";
    private final static String TWO_STAGE_STATUS = "工商注册";
    private final static String THREE_STAGE_STATUS = "前期批复";
    private final static String FOUR_STAGE_STATUS = "落地手续";
    private final static String DEFAULT_CONFIRM = "尚未完成提交相关材料";
    private final static int DEFAULT_COMPLETE = 0;
    private final static int FINISH_COMPLETE = 1;


    @Override
    public PageResult<InfoVO> page(InfoQuery query) {
        IPage<InfoEntity> page = baseMapper.selectPage(getPage(query), getWrapper(query));
        if (CollUtil.isNotEmpty(page.getRecords())) {
            // 获取当前阶段开始时间
            page.getRecords().forEach(this::calculateStatusDuration);

        }
        return new PageResult<>(InfoConvert.INSTANCE.convertList(page.getRecords()), page.getTotal());
    }

    private LambdaQueryWrapper<InfoEntity> getWrapper(InfoQuery query) {
        LambdaQueryWrapper<InfoEntity> wrapper = Wrappers.lambdaQuery();
        wrapper.like(StrUtil.isNotBlank(query.getProjectCode()), InfoEntity::getProjectCode, query.getProjectCode())
                .like(StrUtil.isNotBlank(query.getProjectName()), InfoEntity::getProjectName, query.getProjectName())
                .like(StrUtil.isNotBlank(query.getInvestorName()), InfoEntity::getInvestorName, query.getInvestorName())
                .orderByDesc(InfoEntity::getCreateTime);
        return wrapper;
    }

    /**
     * 计算并设置信息对象的状态持续时间。
     *
     * @param info 包含项目ID和当前状态的信息对象
     */
    public void calculateStatusDuration(InfoEntity info) {
        if (StrUtil.equals(info.getCurrentStatus(), FINISH_STATUS)) {
            // 如果当前状态为已完成，则设置状态持续时间为 "--"
            info.setStatusDuration("--");
        } else {            // 获取当前阶段开始时间
            LocalDateTime startTime = processStagesService.getStarTimeByProjectIdWithStage(info.getId(), info.getCurrentStatus());
            if (startTime != null) {
                // 获取当前时间
                LocalDateTime endTime = LocalDateTime.now();
                // 计算时间差
                Duration duration = Duration.between(startTime, endTime);
                // 分别计算天数、小时数、分钟数
                long days = duration.toDays();
                long hours = duration.minusDays(days).toHours();
                long minutes = duration.minusDays(days).minusHours(hours).toMinutes();

                // 格式化持续时间字符串
                String statusDuration = String.format("%d天%d小时%d分", days, hours, minutes);
                info.setStatusDuration(statusDuration);
            } else {
                // 处理 startTime 为 null 的情况
                info.setStatusDuration("当前阶段开始时间未知");
                log.warn("未找到项目ID {} 在状态 {} 的开始时间", info.getId(), info.getCurrentStatus());
            }
        }
    }

    //将本周进度保存到项目进度表
//    private void saveWeeklyProgress(InfoEntity info) {
//        //通过用户id拿用户名
//        Long creator = info.getCreator();
//        String creatorName = sysUserService.getRealName(creator);
//        ProjectReportEntity reportEntity = new ProjectReportEntity();
//        reportEntity.setProjectId(info.getId());
//        reportEntity.setProgressReport(info.getWeeklyProgress());
//        reportEntity.setCreator(creatorName);
//        reportEntity.setCreateTime(LocalDateTime.now());
//        projectReportService.insert(reportEntity);
//
//    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    // 定义了一个名为 "save" 的方法，该方法接受一个 InfoVO 类型的参数 "vo"
    public void save(InfoVO vo) {
        // 将 "vo" 对象的 ID 设置为 null，可能用于新对象的创建
        vo.setId(null);

        // 获取所有阶段实体的列表
        List<StageEntity> stages = stageService.getAllStages();

        // 将 InfoVO 类型的 "vo" 转换为 InfoEntity 实体
        InfoEntity entity = InfoConvert.INSTANCE.convert(vo);

        // 构建项目信息
        buildProjectInfo(entity);

        // 如果阶段列表为空，则设置默认状态
        if (CollUtil.isEmpty(stages)) {
            entity.setCurrentStatus(DEFAULT_CURRENT_STATUS);
        } else {
            // 否则，设置第一个阶段的名称作为当前状态
            entity.setCurrentStatus(stages.get(0).getName());
            entity.setStatusDuration("--");
        }

        // 插入实体到数据库
        baseMapper.insert(entity);
//        saveWeeklyProgress(entity);
        // 获取所有流程步骤的配置信息
        List<ProcessStepsEntity> processSteps = processStepsService.list();

        // 如果实体 ID 不为空且阶段列表不为空，则开始处理流程阶段数据
        if (Objects.nonNull(entity.getId()) && CollUtil.isNotEmpty(stages)) {

            // 使用 Stream API 映射每个阶段实体并收集为新的 ProcessStagesEntity 列表
            List<ProcessStagesEntity> processStages = stages.stream().map(stage -> {
                ProcessStagesEntity processStage = new ProcessStagesEntity();

                // 设置 ProcessStagesEntity 的属性
                processStage.setId(null);
                processStage.setName(stage.getName());
                processStage.setProjectId(entity.getId());
                processStage.setConfigStageId(stage.getId());

                // 如果是第一阶段，则设置特殊属性
                if (FIRST_STAGE_ID.equals(stage.getId())) {
                    processStage.setStartTime(LocalDateTime.now());
                    processStage.setStart(true);
                    processStage.setFinish(false);
                    processStage.setFinishNode(List.of(FIRST_STAGE_ID));

                }

                return processStage;
            }).collect(Collectors.toList());

            // 批量保存流程阶段实体
            processStagesService.saveBatch(processStages);

            // 处理流程步骤数据
            List<ProcessStatesEntity> processStatesEntities = processSteps.stream().map(processStepsEntity -> {
                ProcessStatesEntity processStatesEntity = new ProcessStatesEntity();

                // 获取步骤所属的阶段 ID
                Long stageId = processStepsEntity.getStageId();

                // 查找与阶段 ID 匹配的第一个 ProcessStagesEntity 并设置其 ID 为步骤的阶段 ID
                Optional<ProcessStagesEntity> first = processStages.stream().filter(processStagesEntity -> processStagesEntity.getConfigStageId().equals(stageId)).findFirst();
                first.ifPresent(processStagesEntity -> processStatesEntity.setStageId(processStagesEntity.getId()));

                // 设置其他属性
                processStatesEntity.setId(null);
                processStatesEntity.setStepId(processStepsEntity.getId());
                processStatesEntity.setProjectId(entity.getId());
                processStatesEntity.setStatus(DEFAULT_CURRENT_STATUS);
                processStatesEntity.setCurrentHandler(processStepsEntity.getHandlerRole());

                // 根据是否需要确认设置确认状态
                Integer needConfirm = processStepsEntity.getNeedConfirm();
                if (NEED_CONFIRM.equals(needConfirm)) {
                    processStatesEntity.setMatlConfirm(DEFAULT_CONFIRM);
                    //初始化流程环节的处理按钮是否启用状态、（判断先后操作顺序等）
                    processStatesEntity.setBranchPath(NEED_CONFIRM);
                }
//            Integer branchPoint = processStepsEntity.getBranchPoint();
//            if (branchPoint==1){
//                processStatesEntity.setBranchPath(branchPoint);
//            }

                // 如果是第一个环节（项目对接），则设置完成状态和其他时间属性
                if (FIRST_STAGE_ID.equals(processStepsEntity.getId())) {
                    processStatesEntity.setStatus(FINISH_STATUS);
                    processStatesEntity.setCompleted(FINISH_COMPLETE);
                    processStatesEntity.setOperatorId(SecurityUser.getUserId());
                    processStatesEntity.setStartTime(LocalDateTime.now());
                    processStatesEntity.setCompletionTime(LocalDateTime.now());
                    processStatesEntity.setBranchPath(1);
                } else {
                    processStatesEntity.setStatus(DEFAULT_CURRENT_STATUS);
                    processStatesEntity.setCompleted(DEFAULT_COMPLETE);
                }


                return processStatesEntity;
            }).collect(Collectors.toList());

            // 批量保存流程步骤实体
            processStatesService.saveBatch(processStatesEntities);


            // Optional<ProcessStagesEntity> firstNode = processStages.stream().filter(processStage -> processStage.getId().equals(FIRST_STAGE_ID)).findFirst();

        }

    }


    private void buildProjectInfo(InfoEntity entity) {
        entity.setStartTime(LocalDateTime.now());
        // 清理项目名称，移除所有标点符号和特殊字符
        String cleanedProjectName = cleanSpecialChars(entity.getProjectName());

        // 年月
        String yearMonth = LocalDate.now().format(DateTimeFormatter.ofPattern(DatePattern.SIMPLE_MONTH_PATTERN));
        // 项目名称前六位
        String projectCodeStart = yearMonth + ConvertUtil.getUppercaseFirstLetter(cleanedProjectName, 6);
        // 两位随机数
        int number = NumberUtil.generateRandomNumber(0, 99, 2)[0];
        // 项目编码
        entity.setProjectCode(projectCodeStart + number);
    }
    /**
     * 移除字符串中的所有标点符号和特殊字符
     * @param input 输入字符串
     * @return 清理后的字符串
     */
    private String cleanSpecialChars(String input) {
        return input.replaceAll("[^A-Za-z0-9]", "");
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void update(InfoVO vo) {
        if (Objects.isNull(vo.getId())) {
            throw new ServerException("项目编号不能为空");
        }
        InfoEntity infoEntity = baseMapper.selectById(vo.getId());
        if (Objects.isNull(infoEntity)) {
            throw new ServerException("修改的项目数据不存在");
        }
        InfoEntity entity = InfoConvert.INSTANCE.convert(vo);
        if (entity.getStartTime() != null) {
            calculateStatusDuration(entity);
        }

        updateById(entity);
//        saveWeeklyProgress(entity);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void delete(List<Long> idList) {
        removeByIds(idList);
    }

    @Override
    public InfoVO getInfoByCode(String code) {
        if (StrUtil.isBlank(code)) {
            return null;
        }
        InfoEntity info = new LambdaQueryChainWrapper<>(baseMapper).eq(InfoEntity::getProjectCode, code).last("limit 1").one();
        if (Objects.isNull(info)) {
            return null;
        }
        calculateStatusDuration(info);
        return InfoConvert.INSTANCE.convert(info);
    }

    @Override
    public InfoVO getInfoById(Long id) {
        if (Objects.isNull(id)) {
            return null;
        }
        InfoEntity infoEntity = baseMapper.selectById(id);
        if (Objects.isNull(infoEntity)) {
            return null;
        }
        calculateStatusDuration(infoEntity);
        return InfoConvert.INSTANCE.convert(infoEntity);
    }

    @Override
    @SneakyThrows
    public void export() {
        List<InfoEntity> list = list();
        // 重新计算每个entity中的StatusDuration的值，使用calculateStatusDuration方法
        list.forEach(this::calculateStatusDuration);
        // 转成VO
        List<InfoVO> infoVOS = InfoConvert.INSTANCE.convertList(list);
        transService.transBatch(infoVOS);
        // 写到浏览器打开
        ExcelUtils.excelExport(InfoVO.class, "project_info_excel" + DateUtils.format(new Date()), null, infoVOS);
    }

    @Override
    public List<InfoEntity> selectUnFinishPorject() {
        return new LambdaQueryChainWrapper<>(baseMapper)
                .ne(InfoEntity::getCurrentStatus, FINISH_STATUS)
                .list();
    }

    @Override
    public ProjectCountVO getInfoCount() {
        ProjectCountVO projectCountVO = new ProjectCountVO();
        // 获取项目总数
        projectCountVO.setProjectCount(Math.toIntExact(new LambdaQueryChainWrapper<>(baseMapper).count()));
        // 获取项目完成总数
        projectCountVO.setCompleteCount(Math.toIntExact(new LambdaQueryChainWrapper<>(baseMapper).eq(InfoEntity::getCurrentStatus, FINISH_STATUS).count()));
        // 获取项目一阶段总数
        projectCountVO.setOneStageCount(Math.toIntExact(new LambdaQueryChainWrapper<>(baseMapper).eq(InfoEntity::getCurrentStatus, ONE_STAGE_STATUS).count()));
        projectCountVO.setTwoStageCount(Math.toIntExact(new LambdaQueryChainWrapper<>(baseMapper).eq(InfoEntity::getCurrentStatus, TWO_STAGE_STATUS).count()));
        projectCountVO.setThreeStageCount(Math.toIntExact(new LambdaQueryChainWrapper<>(baseMapper).eq(InfoEntity::getCurrentStatus, THREE_STAGE_STATUS).count()));
        projectCountVO.setFourStageCount(Math.toIntExact(new LambdaQueryChainWrapper<>(baseMapper).eq(InfoEntity::getCurrentStatus, FOUR_STAGE_STATUS).count()));
        return projectCountVO;
    }

    @Override
    public List<TimeOutInfoVO> getTimeOutInfo() {
        // 获取状态表中有超时环节对应的项目信息
        List<TimeOutInfoVO> timeOutInfos = new ArrayList<>();
        Map<Long, Object[]> stepInfoMap = loadStepInfoMap(); // 新增方法，用于加载步骤信息到 map

        // 获取所有未完成且计时器已启动的状态
        List<ProcessStatesEntity> states = new LambdaQueryChainWrapper<>(processStatesDao)
                .eq(ProcessStatesEntity::getCompleted, 0)
                .eq(ProcessStatesEntity::getTimerStarted, 1)
                .list();

        // 筛选出超时的环节，并收集相关信息
        for (ProcessStatesEntity state : states) {
            Object[] stepInfo = stepInfoMap.get(state.getStepId());
            if (stepInfo != null) {
                Integer deadline = (Integer) stepInfo[2];
                if (deadline > 0 && isOverDeadline(state.getStartTime(), deadline)) {
                    InfoVO info = getInfoById(state.getProjectId());
                    TimeOutInfoVO timeOutInfoVO = new TimeOutInfoVO();
                    timeOutInfoVO.setProjectCode(info.getProjectCode());
                    timeOutInfoVO.setProjectName(info.getProjectName());
                    timeOutInfoVO.setStepName((String) stepInfo[1]);
                    timeOutInfoVO.setDuration(calculateDuration(state.getStartTime(), LocalDateTime.now()));
                    timeOutInfoVO.setWeeklyProgress(info.getWeeklyProgress());
                    timeOutInfos.add(timeOutInfoVO);
                }
            }
        }
        return timeOutInfos;
    }

    @Override
    public PageResult<InfoWithStatesVO> plzPage(SimpleSearchVO simpleSearchVO) {
        int page = simpleSearchVO.getPage();
        IPage<InfoEntity> searchPage = Page.of(page, simpleSearchVO.getSize());
        String projectName = simpleSearchVO.getProjectName();
        String projectCode = simpleSearchVO.getProjectCode();
        String investorName = simpleSearchVO.getInvestorName();

        IPage<InfoEntity> pageResult = new LambdaQueryChainWrapper<>(baseMapper)
                .like(StrUtil.isNotBlank(projectName), InfoEntity::getProjectName, projectName)
                .like(StrUtil.isNotBlank(projectCode), InfoEntity::getProjectCode, projectCode)
                .like(StrUtil.isNotBlank(investorName), InfoEntity::getInvestorName, investorName)
                .orderByDesc(InfoEntity::getCreateTime)
                .page(searchPage);
        List<InfoVO> infoVOList = InfoConvert.INSTANCE.convertList(pageResult.getRecords());
        // 加载状态信息
        Map<Long, Object[]> stepInfoMap = loadStepInfoMap();
        List<InfoWithStatesVO> infoWithStatesVOS = new ArrayList<>();
        for (InfoVO info : infoVOList) {
            InfoWithStatesVO infoWithStatesVO = new InfoWithStatesVO();
            infoWithStatesVO.setProjectCode(info.getProjectCode());
            infoWithStatesVO.setProjectName(info.getProjectName());
            infoWithStatesVO.setId(info.getId());
            infoWithStatesVO.setInvestorName(info.getInvestorName());
            infoWithStatesVO.setWeeklyProgress(info.getWeeklyProgress());
            infoWithStatesVO.setContactPhone(info.getContactPhone());
            infoWithStatesVO.setContactName(info.getContactName());
            infoWithStatesVO.setEndTime(info.getEndTime());
            infoWithStatesVO.setStartTime(info.getStartTime());
            infoWithStatesVO.setConstructionContent(info.getConstructionContent());
            infoWithStatesVO.setIndustryCategory(info.getIndustryCategory());
            infoWithStatesVO.setLeaderPhone(info.getLeaderPhone());
            infoWithStatesVO.setRemark(info.getRemark());
            infoWithStatesVO.setLinkedLeader(info.getLinkedLeader());
            infoWithStatesVO.setLinkedDepartment(info.getLinkedDepartment());
            infoWithStatesVO.setProjectLeader(info.getProjectLeader());
            infoWithStatesVO.setCurrentStatus(info.getCurrentStatus());
            infoWithStatesVO.setPlannedInvestment(info.getPlannedInvestment());
            infoWithStatesVO.setLinkedLeaderPhone(info.getLinkedLeaderPhone());
            infoWithStatesVO.setStatusDuration(info.getStatusDuration());

            // 获取当前状态信息
            float ProgressPercentage = processStatesService.getProgressPercentageByProjectId(info.getId());
            infoWithStatesVO.setProgressPercentage(ProgressPercentage);
//            项目是否有环节逾期
            boolean isOverdueStates = processStatesService.getIsOverdueStates(info.getId());
            infoWithStatesVO.setOverdue(isOverdueStates);
            infoWithStatesVOS.add(infoWithStatesVO);
        }
        return new PageResult<>(infoWithStatesVOS, pageResult.getTotal());
    }

    // 加载步骤信息到 map 的方法
    private Map<Long, Object[]> loadStepInfoMap() {
        Map<Long, Object[]> stepInfoMap = new HashMap<>();
        List<Object[]> allStepDeadLines = processStepsService.getAllStepDeadLine();
        for (Object[] info : allStepDeadLines) {
            Long stepId = (Long) info[0];
            stepInfoMap.put(stepId, info);
        }
        return stepInfoMap;
    }
    // 辅助函数，判断是否超过时限
    private boolean isOverDeadline(LocalDateTime startTime, int deadline) {
        LocalDateTime deadlineTime = startTime.plusDays(deadline);
        return LocalDateTime.now().isAfter(deadlineTime);
    }

    // 辅助函数，计算两个时间点之间的时长
    private String calculateDuration(LocalDateTime startTime, LocalDateTime endTime) {
        Duration duration = Duration.between(startTime, endTime);
        long days = duration.toDays();
        long hours = duration.minusDays(days).toHours();
        long minutes = duration.minusDays(days).minusHours(hours).toMinutes();
        return String.format("%d天%d时%d分", days, hours, minutes);
    }
    @Override
    public PageResult<SimpleInfoVO> getSimpleInfos(SimpleSearchVO simpleSearchVO) {
        int page = simpleSearchVO.getPage();
        IPage<InfoEntity> searchPage = Page.of(page, simpleSearchVO.getSize());
        String projectName = simpleSearchVO.getProjectName();
        String projectCode = simpleSearchVO.getProjectCode();
        String investorName = simpleSearchVO.getInvestorName();

        IPage<InfoEntity> pageResult = new LambdaQueryChainWrapper<>(baseMapper)
                .like(StrUtil.isNotBlank(projectName), InfoEntity::getProjectName, projectName)
                .like(StrUtil.isNotBlank(projectCode), InfoEntity::getProjectCode, projectCode)
                .like(StrUtil.isNotBlank(investorName), InfoEntity::getInvestorName, investorName)
                .orderByDesc(InfoEntity::getCreateTime)
                .page(searchPage);

        return new PageResult<>(InfoConvert.INSTANCE.convertSimples(pageResult.getRecords()), pageResult.getTotal());

    }


}